﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace fabao.Common.Util
{
    public static class StringHelper
    {
        /// <summary>
        /// 字符串全部替换
        /// </summary>
        /// <param name="source"></param>
        /// <param name="oldString"></param>
        /// <param name="newString"></param>
        /// <returns></returns>
        public static string ReplaceAll(string source, string oldString, string newString)
        {
            if (string.IsNullOrEmpty(source))
            {
                return "";
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append(source);
            return stringBuilder.Replace(oldString, newString).ToString();
        }
        /// <summary>
        /// 随机生成密码
        /// </summary>
        /// <returns></returns>
        public static string RandomPwd()
        {
            //可选字符
            const string lowercaseChars = "abcdefghijklmnopqrstuvwxyz";
            const string uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            const string digitChars = "0123456789";
            const string specialChars = "!@#$%^&*()_+-=[]{}|;:,.<>?";

            string allChars = lowercaseChars + uppercaseChars + digitChars + specialChars;

            //设置密码长度范围
            int minLength = 8;
            int maxLength = 16;
            //密码长度
            int passwordLength = new Random().Next(minLength, maxLength + 1);
            char[] password = new char[passwordLength];
            //确保至少包含一个小写字母、一个大写字母、一个数字和一个特殊字符
            password[0] = lowercaseChars[new Random().Next(lowercaseChars.Length)];
            password[1] = uppercaseChars[new Random().Next(uppercaseChars.Length)];
            password[2] = digitChars[new Random().Next(digitChars.Length)];
            password[3] = specialChars[new Random().Next(specialChars.Length)];
            //生成其他字符
            for (int i = 4; i < passwordLength; i++)
            {
                byte[] randomBytes = new byte[1];
                var ran = RandomNumberGenerator.Create();
                ran.GetBytes(randomBytes);
                int randomIndex = randomBytes[0] % allChars.Length;
                password[i] = allChars[randomIndex];
            }

            //打乱顺序
            for (int i = 0; i < passwordLength; i++)
            {
                int randomIndex = new Random().Next(passwordLength);
                char temp = password[i];
                password[i] = password[randomIndex];
                password[randomIndex] = temp;
            }
            return new string(password);
        }

        /// <summary>
        /// 替换特殊符号
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string RemoveSpecialString(string str, string retstr = "")
        {
            str = str.Replace(@"/", retstr);
            str = str.Replace(@"\", retstr);
            str = str.Replace(@":", retstr);
            str = str.Replace(@"?", retstr);
            str = str.Replace("\"", retstr);
            str = str.Replace(@"<", retstr);
            str = str.Replace(@">", retstr);
            str = str.Replace(@"|", retstr);
            return str;
        }

        /// <summary>
        /// 去掉文件及文件夹的非法字符
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static string FileIlegalReplace(string filename)
        {
            char[] invalidChars = Path.GetInvalidPathChars();
            char[] Chars = Path.GetInvalidFileNameChars();

            StringBuilder rBuilder = new StringBuilder(filename);
            foreach (char rInvalidChar in invalidChars)
                rBuilder.Replace(rInvalidChar.ToString(), string.Empty);

            foreach (char rInvalidChar in Chars)
                rBuilder.Replace(rInvalidChar.ToString(), string.Empty);

            return rBuilder.ToString().Trim();
        }

        /// <summary>
        /// 字典排序拼接
        /// </summary>
        /// <param name="paramsmap"></param>
        /// <returns></returns>
        public static string Getparamsrc(Dictionary<string, object> paramsmap)
        {
            var vdic = (from objdic in paramsmap orderby objdic.Key ascending select objdic);
            StringBuilder str = new StringBuilder();
            foreach (KeyValuePair<string, object> kv in vdic)
            {
                string pkey = kv.Key;
                if (!string.IsNullOrEmpty(pkey))
                {
                    if (pkey.Equals("sign"))
                    {
                        continue;
                    }
                    string pvalue = kv.Value.ToString();
                    str.Append(pkey + "=" + pvalue + "&");
                }
            }
            string result = str.ToString().Substring(0, str.ToString().Length - 1);
            return result;
        }

        /// <summary>
        /// DES加密->base64加密->结果
        /// </summary>
        /// <param name="data">加密数据</param>
        /// <param name="key">8位字符的密钥字符串</param>
        /// <param name="iv">8位字符的初始化向量字符串</param>
        /// <returns></returns>
        public static string DESEncrypt(string data, string key = "officemi", string iv = "officeiv", bool pushRandom = true)
        {
            byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(key);
            byte[] byIV = System.Text.ASCIIEncoding.ASCII.GetBytes(iv);

            DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
            int i = cryptoProvider.KeySize;
            MemoryStream ms = new MemoryStream();
            CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateEncryptor(byKey, byIV), CryptoStreamMode.Write);

            StreamWriter sw = new StreamWriter(cst);
            sw.Write(data);
            sw.Flush();
            cst.FlushFinalBlock();
            sw.Flush();
            string desstring = Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);

            ms.Dispose();
            cst.Dispose();
            sw.Dispose();
            cryptoProvider.Dispose();
            byte[] by = System.Text.ASCIIEncoding.ASCII.GetBytes(desstring);
            string result = Convert.ToBase64String(by, 0, by.Length);
            if (pushRandom)
            {
                result += "-" + GenerateCheckCode(8);
            }
            return result;
        }

        /// <summary>
        /// base64解密->DES解密->结果
        /// </summary>
        /// <param name="data">解密数据</param>
        /// <param name="key">8位字符的密钥字符串(需要和加密时相同)</param>
        /// <param name="iv">8位字符的初始化向量字符串(需要和加密时相同)</param>
        /// <returns></returns>
        public static string DESDecrypt(string data, string key = "officemi", string iv = "officeiv", bool pushRandom = true)
        {
            byte[] byKey = System.Text.ASCIIEncoding.ASCII.GetBytes(key);
            byte[] byIV = System.Text.ASCIIEncoding.ASCII.GetBytes(iv);

            byte[] byEnc;
            try
            {
                if (pushRandom)
                {
                    data = data.Split('-')[0];
                }
                byte[] bybase = Convert.FromBase64String(data);
                string data2 = System.Text.Encoding.ASCII.GetString(bybase, 0, bybase.Length);
                byEnc = Convert.FromBase64String(data2);

                DESCryptoServiceProvider cryptoProvider = new DESCryptoServiceProvider();
                MemoryStream ms = new MemoryStream(byEnc);
                CryptoStream cst = new CryptoStream(ms, cryptoProvider.CreateDecryptor(byKey, byIV), CryptoStreamMode.Read);
                StreamReader sr = new StreamReader(cst);
                string retstring = sr.ReadToEnd();

                ms.Dispose();
                cst.Dispose();
                sr.Dispose();
                cryptoProvider.Dispose();
                return retstring;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 生成随机字母字符串(数字字母混和)
        /// </summary>
        /// <param name="codeCount">待生成的位数</param>
        /// <returns>生成的字母字符串</returns>
        public static string GenerateCheckCode(int codeCount)
        {
            int rep = 0;
            string str = string.Empty;
            long num2 = DateTime.Now.Ticks + rep;
            rep++;
            Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep)));
            for (int i = 0; i < codeCount; i++)
            {
                char ch;
                int num = random.Next();
                if ((num % 2) == 0)
                {
                    ch = (char)(0x30 + ((ushort)(num % 10)));
                }
                else
                {
                    ch = (char)(0x41 + ((ushort)(num % 0x1a)));
                }
                str = str + ch.ToString();
            }
            return str;
        }

        /// <summary>
        /// 流转字符串
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static string StreamToString(Stream stream)
        {
            if (stream == null || !stream.CanRead)
            {
                return string.Empty;
            }
            stream.Position = 0;
            using (StreamReader reader = new StreamReader(stream))
            {
                return reader.ReadToEnd();
            }
        }

        /// <summary>
        /// 字符串转哈希(BKDRHash)
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string StringToHash(this string str)
        {
            int seed = 13131; // 31 131 1313 13131 131313 etc..   
            int hash = 0;

            for (int i = 0; i < str.Length; i++)
            {
                hash = hash * seed + str[i];
            }

            return string.Concat(hash & 0x7FFFFFFF);
        }

        /// <summary>
        /// 符号分割字符串转换成int数组
        /// </summary>
        /// <param name="splitStr"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static List<int> TryGetIntListBySplitString(string splitStr, char separator = ',')
        {
            try
            {
                return splitStr?.Trim().Split(separator).Select(u => Convert.ToInt32(u)).Distinct().ToList() ?? new List<int>();
            }
            catch
            {
                return new List<int>();
            }
        }

        /// <summary>
        /// 比较两个字符分割字符内容是否完全一致
        /// </summary>
        /// <param name="splitStr1">值1</param>
        /// <param name="splitStr2">值2</param>
        /// <param name="separator">分割符</param>
        /// <returns></returns>
        public static bool CompareSplitString(string splitStr1, string splitStr2, char separator = ',')
        {
            if (splitStr1.Equals(splitStr2))
                return true;

            var array1 = splitStr1?.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries) ?? new string[] { };
            var array2 = splitStr2?.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries) ?? new string[] { };
            return array1.OrderBy(s => s).SequenceEqual(array2.OrderBy(s => s));
        }

        /// <summary>
        /// 将int值拼接的字符转换成对应枚举值描述名称字符
        /// </summary>
        /// <remarks>
        /// 例如："1,2,3" 转换成 "名称1,名称2,名称3"
        /// </remarks>
        /// <param name="splitStr">值</param>
        /// <param name="separator">分割符</param>
        /// <returns></returns>
        public static string TryToEnumDescriptionNameSplitString<EnumType>(string splitStr, char separator = ',') where EnumType : Enum
        {
            try
            {
                var list = TryGetIntListBySplitString(splitStr, separator);
                if (!list.Any())
                    return string.Empty;

                var result = new List<string>();
                var enumType = typeof(EnumType);
                foreach (var value in list)
                {
                    var enumValue = Enum.ToObject(enumType, value);
                    var description = EnumHelper.GetEnumDescription(enumValue);
                    result.Add(description);
                }

                return string.Join(separator, result);
            }
            catch
            {
                return string.Empty;
            }
        }
    }
}
